{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=\"red\">注</font>: 使用 tensorboard 可视化需要安装 tensorflow (TensorBoard依赖于tensorflow库，可以任意安装tensorflow的gpu/cpu版本)\n",
    "\n",
    "```shell\n",
    "pip install tensorflow-cpu\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:16:50.110697Z",
     "start_time": "2025-01-30T13:16:50.104734Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.1\n",
      "torch 2.5.1+cpu\n",
      "cpu\n"
     ]
    }
   ],
   "execution_count": 25
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据准备"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:16:53.794635Z",
     "start_time": "2025-01-30T13:16:53.739566Z"
    }
   },
   "source": [
    "from torchvision import datasets\n",
    "from torchvision.transforms import ToTensor\n",
    "from torch.utils.data import random_split\n",
    "\n",
    "# fashion_mnist图像分类数据集\n",
    "train_ds = datasets.FashionMNIST(\n",
    "    root=\"data\",\n",
    "    train=True,\n",
    "    download=True,\n",
    "    transform=ToTensor()\n",
    ")\n",
    "\n",
    "test_ds = datasets.FashionMNIST(\n",
    "    root=\"data\",\n",
    "    train=False,\n",
    "    download=True,\n",
    "    transform=ToTensor()\n",
    ")\n",
    "print(len(train_ds), len(test_ds))\n",
    "seed = 42\n",
    "# torchvision 数据集里没有提供训练集和验证集的划分\n",
    "# 这里用 random_split 按照 11 : 1 的比例来划分数据集\n",
    "train_ds, val_ds = random_split(train_ds, [55000, 5000], torch.Generator().manual_seed(seed))"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "60000 10000\n"
     ]
    }
   ],
   "execution_count": 26
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:17:01.825285Z",
     "start_time": "2025-01-30T13:16:56.033847Z"
    }
   },
   "source": [
    "from torchvision.transforms import Normalize\n",
    "\n",
    "# 遍历train_ds得到每张图片，计算每个通道的均值和方差\n",
    "def cal_mean_std(ds):\n",
    "    mean = 0.\n",
    "    std = 0.\n",
    "    for img, _ in ds:\n",
    "        mean += img.mean(dim=(1, 2))\n",
    "        std += img.std(dim=(1, 2))\n",
    "    mean /= len(ds)\n",
    "    std /= len(ds)\n",
    "    return mean, std\n",
    "\n",
    "\n",
    "print(cal_mean_std(train_ds))\n",
    "# 0.2860， 0.3205\n",
    "transforms = nn.Sequential(\n",
    "    Normalize([0.2856], [0.3202])\n",
    ") # 对每个通道进行标准化"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(tensor([0.2856]), tensor([0.3202]))\n"
     ]
    }
   ],
   "execution_count": 27
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "ExecuteTime": {
     "end_time": "2025-01-30T13:17:01.830258Z",
     "start_time": "2025-01-30T13:17:01.826267Z"
    }
   },
   "source": [
    "img, label = train_ds[0]\n",
    "img.shape, label"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([1, 28, 28]), 9)"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 28
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:17:01.835239Z",
     "start_time": "2025-01-30T13:17:01.830258Z"
    }
   },
   "source": [
    "from torch.utils.data.dataloader import DataLoader\n",
    "\n",
    "batch_size = 32\n",
    "# 从数据集到dataloader\n",
    "train_loader = DataLoader(train_ds, batch_size=batch_size, shuffle=True, num_workers=4)\n",
    "val_loader = DataLoader(val_ds, batch_size=batch_size, shuffle=False, num_workers=4)\n",
    "test_loader = DataLoader(test_ds, batch_size=batch_size, shuffle=False, num_workers=4)"
   ],
   "outputs": [],
   "execution_count": 29
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:17:03.670901Z",
     "start_time": "2025-01-30T13:17:03.655461Z"
    }
   },
   "source": [
    "class CNN(nn.Module):\n",
    "    def __init__(self, activation=\"relu\"):\n",
    "        super().__init__()\n",
    "        self.activation = F.relu if activation == \"relu\" else F.selu\n",
    "        #输入通道数，图片是灰度图，所以是1，图片是彩色图，就是3，输出通道数，就是卷积核的个数（32,1,28,28）\n",
    "        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1)\n",
    "        #输入x(32,32,28,28) 输出x(32,32,28,28)\n",
    "        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=1)\n",
    "        self.pool = nn.MaxPool2d(2, 2) #池化核大小为2（2*2），步长为2，（28-2)//2+1=14，输出x(32,32,14,14)\n",
    "        # 输入x(32,32,14,14) 输出x(32,64,14,14)，池化不改变通道数\n",
    "        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv4 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv5 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.conv6 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.flatten = nn.Flatten()\n",
    "        # input shape is (28, 28, 1) so the fc1 layer in_features is 128 * 3 * 3\n",
    "        self.fc1 = nn.Linear(128 * 3 * 3, 128)\n",
    "        self.fc2 = nn.Linear(128, 10) #输出尺寸（32,10）\n",
    "\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "\n",
    "    def forward(self, x):\n",
    "        act = self.activation\n",
    "        # 2层卷积1层池化\n",
    "        x = self.pool(act(self.conv2(act(self.conv1(x))))) # 1 * 28 * 28 -> 32 * 14 * 14\n",
    "        #print(x.shape)\n",
    "        x = self.pool(act(self.conv4(act(self.conv3(x))))) # 32 * 14 * 14 -> 64 * 7 * 7\n",
    "        #print(x.shape)\n",
    "        x = self.pool(act(self.conv6(act(self.conv5(x))))) # 64 * 7 * 7 -> 128 * 3 * 3\n",
    "        #print(x.shape)\n",
    "        x = self.flatten(x) # 128 * 3 * 3 ->1152\n",
    "        x = act(self.fc1(x)) # 1152 -> 128\n",
    "        x = self.fc2(x) # 128 -> 10\n",
    "        return x\n",
    "\n",
    "\n",
    "for idx, (key, value) in enumerate(CNN().named_parameters()):\n",
    "    print(f\"{key}\\tparamerters num: {np.prod(value.shape)}\") # 打印模型的参数信息"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conv1.weight\tparamerters num: 288\n",
      "conv1.bias\tparamerters num: 32\n",
      "conv2.weight\tparamerters num: 9216\n",
      "conv2.bias\tparamerters num: 32\n",
      "conv3.weight\tparamerters num: 18432\n",
      "conv3.bias\tparamerters num: 64\n",
      "conv4.weight\tparamerters num: 36864\n",
      "conv4.bias\tparamerters num: 64\n",
      "conv5.weight\tparamerters num: 73728\n",
      "conv5.bias\tparamerters num: 128\n",
      "conv6.weight\tparamerters num: 147456\n",
      "conv6.bias\tparamerters num: 128\n",
      "fc1.weight\tparamerters num: 147456\n",
      "fc1.bias\tparamerters num: 128\n",
      "fc2.weight\tparamerters num: 1280\n",
      "fc2.bias\tparamerters num: 10\n"
     ]
    }
   ],
   "execution_count": 30
  },
  {
   "cell_type": "code",
   "source": [
    "# 看看模型\n",
    "activation = \"relu\"\n",
    "model = CNN(activation)\n",
    "# model.to(device)\n",
    "img = torch.randn(1, 1, 28, 28)\n",
    "model(img)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-01-30T13:07:37.284138Z",
     "start_time": "2025-01-30T13:07:37.121834Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([1, 32, 14, 14])\n",
      "torch.Size([1, 64, 7, 7])\n",
      "torch.Size([1, 128, 3, 3])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.0727,  0.1298,  0.0262,  0.0316,  0.0053, -0.1971, -0.0584,  0.0474,\n",
       "          0.0026,  0.0152]], grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 15
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:45:47.816268Z",
     "start_time": "2025-01-30T13:45:47.803556Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 练习不同尺寸的卷积核，padding，stride的效果\n",
    "class CNN1(nn.Module):\n",
    "    def __init__(self, activation=\"relu\"):\n",
    "        super().__init__()\n",
    "        self.activation = F.relu if activation == \"relu\" else F.selu\n",
    "        #输入通道数，图片是灰度图，所以是1，图片是彩色图，就是3，输出通道数，就是卷积核的个数（32,1,28,28）\n",
    "        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=5,padding=2,stride=2)\n",
    "        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=1)\n",
    "        self.pool = nn.MaxPool2d(2, 2) #池化核大小为2（2*2），步长为2\n",
    "        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv4 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv5 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.conv6 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.flatten = nn.Flatten()\n",
    "        # input shape is (28, 28, 1) so the fc1 layer in_features is 128 * 3 * 3\n",
    "        self.fc1 = nn.Linear(128, 32)\n",
    "        self.fc2 = nn.Linear(32, 10) #输出尺寸（32,10）\n",
    "\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "\n",
    "    def forward(self, x):\n",
    "        act = self.activation\n",
    "        x=act(self.conv1(x)) # 1 * 28 * 28 -> 32 * 14 * 14\n",
    "        print(x.shape)\n",
    "        x=act(self.conv2(x)) # 32 * 14 * 14 -> 32 * 14 * 14\n",
    "        print(x.shape)\n",
    "        x = self.pool(x) # 32 * 14 * 14 -> 32 * 7 * 7\n",
    "        print(x.shape)\n",
    "        x=act(self.conv3(x)) # 32 * 7 * 7 -> 64 * 7 * 7\n",
    "        print(x.shape)\n",
    "        x=act(self.conv4(x)) # 64 * 7 * 7 -> 64 * 7 * 7\n",
    "        print(x.shape)\n",
    "        x = self.pool(x) # 64 * 7 * 7 -> 64 * 3 * 3\n",
    "        print(x.shape)\n",
    "        x=act(self.conv5(x)) # 64 * 3 * 3 -> 128 * 3 * 3\n",
    "        print(x.shape)\n",
    "        x=act(self.conv6(x)) # 128 * 3 * 3 -> 128 * 3 * 3\n",
    "        print(x.shape)\n",
    "        x = self.pool(x) # 128 * 3 * 3 -> 128 * 1 * 1\n",
    "        print(x.shape)\n",
    "        x = self.flatten(x) # 128 * 1 * 1 ->128\n",
    "        x = act(self.fc1(x)) # 128 -> 32\n",
    "        x = self.fc2(x) # 32 -> 10\n",
    "        return x\n",
    "\n",
    "# 看看模型\n",
    "activation = \"relu\"\n",
    "model = CNN1(activation)\n",
    "# model.to(device)\n",
    "img = torch.randn(1, 1, 28, 28)\n",
    "model(img)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([1, 32, 14, 14])\n",
      "torch.Size([1, 32, 14, 14])\n",
      "torch.Size([1, 32, 7, 7])\n",
      "torch.Size([1, 64, 7, 7])\n",
      "torch.Size([1, 64, 7, 7])\n",
      "torch.Size([1, 64, 3, 3])\n",
      "torch.Size([1, 128, 3, 3])\n",
      "torch.Size([1, 128, 3, 3])\n",
      "torch.Size([1, 128, 1, 1])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.0108,  0.0672, -0.1108, -0.0305,  0.0031, -0.0641, -0.0129, -0.0667,\n",
       "          0.1032,  0.0028]], grad_fn=<AddmmBackward0>)"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 57
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conv1.weight\tparamerters num: 288\n",
      "conv1.bias\tparamerters num: 32\n",
      "conv2.weight\tparamerters num: 9216\n",
      "conv2.bias\tparamerters num: 32\n",
      "conv3.weight\tparamerters num: 18432\n",
      "conv3.bias\tparamerters num: 64\n",
      "conv4.weight\tparamerters num: 36864\n",
      "conv4.bias\tparamerters num: 64\n",
      "conv5.weight\tparamerters num: 73728\n",
      "conv5.bias\tparamerters num: 128\n",
      "conv6.weight\tparamerters num: 147456\n",
      "conv6.bias\tparamerters num: 128\n",
      "fc1.weight\tparamerters num: 147456\n",
      "fc1.bias\tparamerters num: 128\n",
      "fc2.weight\tparamerters num: 1280\n",
      "fc2.bias\tparamerters num: 10\n"
     ]
    }
   ],
   "source": [
    "class CNN2(nn.Module):\n",
    "    def __init__(self, activation=\"relu\"):\n",
    "        super(CNN, self).__init__()\n",
    "        self.activation = F.relu if activation == \"relu\" else F.selu\n",
    "        #输入通道数，图片是灰度图，所以是1，图片是彩色图，就是3，输出通道数，就是卷积核的个数（32,1,28,28）\n",
    "        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding=1)\n",
    "        #输入x(32,32,28,28) 输出x(32,32,28,28)\n",
    "        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=1)\n",
    "        self.pool = nn.MaxPool2d(2, 2) #池化核大小为2（2*2），步长为2\n",
    "        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv4 = nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, padding=1)\n",
    "        self.conv5 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.conv6 = nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, padding=1)\n",
    "        self.flatten = nn.Flatten()\n",
    "        # input shape is (28, 28, 1) so the fc1 layer in_features is 128 * 3 * 3\n",
    "        self.fc1 = nn.Linear(128 * 3 * 3, 128)\n",
    "        self.fc2 = nn.Linear(128, 10) #输出尺寸（32,10）\n",
    "\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "\n",
    "    def forward(self, x):\n",
    "        act = self.activation\n",
    "        x=act(self.conv1(x)) # 1 * 28 * 28 -> 32 * 28 * 28\n",
    "        print(x.shape)\n",
    "        x=act(self.conv2(x)) # 32 * 28 * 28 -> 32 * 28 * 28\n",
    "        print(x.shape)\n",
    "        x = self.pool(x) # 32 * 28 * 28 -> 32 * 14 * 14\n",
    "        print(x.shape)\n",
    "        x=act(self.conv3(x)) # 32 * 14 * 14 -> 64 * 14 * 14\n",
    "        print(x.shape)\n",
    "        x=act(self.conv4(x)) # 64 * 14 * 14 -> 64 * 14 * 14\n",
    "        print(x.shape)\n",
    "        x = self.pool(x) # 32 * 14 * 14 -> 64 * 7 * 7\n",
    "        print(x.shape)\n",
    "        x=act(self.conv5(x)) # 64 * 7 * 7 -> 128 * 7 * 7\n",
    "        print(x.shape)\n",
    "        x=act(self.conv6(x)) # 128 * 7 * 7 -> 128 * 7 * 7\n",
    "        print(x.shape)\n",
    "        x = self.pool(x) # 128 * 7 * 7 -> 128 * 3 * 3\n",
    "        print(x.shape)\n",
    "        x = self.flatten(x) # 128 * 3 * 3 ->1152\n",
    "        x = act(self.fc1(x)) # 1152 -> 128\n",
    "        x = self.fc2(x) # 128 -> 10\n",
    "        return x\n",
    "\n",
    "\n",
    "for idx, (key, value) in enumerate(CNN().named_parameters()):\n",
    "    print(f\"{key}\\tparamerters num: {np.prod(value.shape)}\") # 打印模型的参数信息\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-07-23T03:04:53.570608600Z",
     "start_time": "2024-07-23T03:04:53.551722300Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "ExecuteTime": {
     "end_time": "2024-07-23T03:05:30.672068100Z",
     "start_time": "2024-07-23T03:05:30.645081600Z"
    }
   },
   "outputs": [],
   "source": [
    "activation = \"relu\"\n",
    "model = CNN(activation)\n",
    "# model.to(device)\n",
    "# img = torch.randn(1, 1, 28, 28)\n",
    "# model(img)"
   ]
  },
  {
   "cell_type": "code",
   "source": [
    "from torchviz import make_dot\n",
    "\n",
    "# 假设你的模型已经定义并命名为 'model'\n",
    "# 构造一个虚拟输入\n",
    "dummy_input = torch.randn(1, 1, 28, 28)  # 替换为你的输入形状\n",
    "\n",
    "# 前向传播以生成计算图\n",
    "output = model(dummy_input)\n",
    "\n",
    "# 可视化模型架构\n",
    "dot = make_dot(output, params=dict(model.named_parameters()))\n",
    "dot.render(\"model_CNN\", format=\"png\")\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-01-30T13:13:04.337236Z",
     "start_time": "2025-01-30T13:13:04.108809Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([1, 32, 14, 14])\n",
      "torch.Size([1, 64, 7, 7])\n",
      "torch.Size([1, 128, 3, 3])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'model_CNN.png'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 18
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "ExecuteTime": {
     "end_time": "2025-01-30T13:13:41.137264Z",
     "start_time": "2025-01-30T13:13:41.131190Z"
    }
   },
   "source": [
    "# 练习计算参数量\n",
    "print(f'conv1 - {1*3*3*32}') # 32个卷积核，每个卷积核大小为1*3*3\n",
    "print(f'conv2 - {32*3*3*32}') # 32个卷积核，每个卷积核大小为32*3*3\n",
    "print(f'conv3 - {32*3*3*64}')\n",
    "print(f'conv4 - {64*3*3*64}')\n",
    "print(f'conv5 - {64*3*3*128}')\n",
    "print(f'conv6 - {128*3*3*128}')\n",
    "print(f'fc1 - {1152*128}')\n",
    "print(f'fc2 - {128*10}')\n",
    "\n",
    "#对上面求和，总参数数目为：\n",
    "1*3*3*32 +32+ 32*3*3*32 +32+ 32*3*3*64 +64+ 64*3*3*64+64 + 64*3*3*128 +128+ 128*3*3*128 +128+ 128*3*3*128+128 + 128*10+10"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conv1 - 288\n",
      "conv2 - 9216\n",
      "conv3 - 18432\n",
      "conv4 - 36864\n",
      "conv5 - 73728\n",
      "conv6 - 147456\n",
      "fc1 - 147456\n",
      "fc2 - 1280\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "435306"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 19
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练\n",
    "\n",
    "pytorch的训练需要自行实现，包括\n",
    "1. 定义损失函数\n",
    "2. 定义优化器\n",
    "3. 定义训练步\n",
    "4. 训练"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:17:31.382339Z",
     "start_time": "2025-01-30T13:17:31.378283Z"
    }
   },
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)              # 验证集预测\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item()) # 将验证集损失加入列表\n",
    "        \n",
    "        preds = logits.argmax(axis=-1)    # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist()) # 将验证集预测结果加入列表\n",
    "        label_list.extend(labels.cpu().numpy().tolist())# 将验证集真实标签加入列表\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list) # 计算验证集准确率\n",
    "    return np.mean(loss_list), acc # 返回验证集损失均值和准确率\n"
   ],
   "outputs": [],
   "execution_count": 31
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:17:31.983122Z",
     "start_time": "2025-01-30T13:17:31.978208Z"
    }
   },
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "outputs": [],
   "execution_count": 32
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:17:33.142490Z",
     "start_time": "2025-01-30T13:17:33.137901Z"
    }
   },
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "outputs": [],
   "execution_count": 33
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:17:33.829160Z",
     "start_time": "2025-01-30T13:17:33.816751Z"
    }
   },
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1)\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                    \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 20\n",
    "\n",
    "activation = \"relu\"\n",
    "model = CNN(activation)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用SGD\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(f\"checkpoints/cnn-{activation}\", save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=10)"
   ],
   "outputs": [],
   "execution_count": 34
  },
  {
   "cell_type": "code",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "ExecuteTime": {
     "end_time": "2025-01-30T13:31:32.773281Z",
     "start_time": "2025-01-30T13:17:35.784633Z"
    }
   },
   "source": [
    "model = model.to(device)\n",
    "record = training(\n",
    "    model,\n",
    "    train_loader,\n",
    "    val_loader,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=1000\n",
    "    )"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/34380 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "7fbcd37c478d418c81373f22b84b8909"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Early stop at epoch 13 / global_step 24000\n"
     ]
    }
   ],
   "execution_count": 35
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:34:43.226200Z",
     "start_time": "2025-01-30T13:34:43.046098Z"
    }
   },
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=500)  #横坐标是 steps"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 37
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-30T13:34:56.907130Z",
     "start_time": "2025-01-30T13:34:50.554987Z"
    }
   },
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(f\"checkpoints/cnn-{activation}/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, test_loader, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ],
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\29470\\AppData\\Local\\Temp\\ipykernel_10320\\2338844456.py:4: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n",
      "  model.load_state_dict(torch.load(f\"checkpoints/cnn-{activation}/best.ckpt\", map_location=\"cpu\"))\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.2832\n",
      "accuracy: 0.8982\n"
     ]
    }
   ],
   "execution_count": 38
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
